// Phong-Blinn Lighting Effect
-- `Tangent.Vertex`		// Tangent space transformations

uniform vec3 fvEyePosition;		// Eye position vector

out vec2 Texcoord;				// Output texture coordinate
out vec3 ViewDirection;			// Output view direction vector
out vec3 LightDirection;		// Output light direction vector
out float Distance;				// Output from light to vertex distance

in vec3 ifvTangent;				// Input tangent vector attribute
in vec3 ifvBinormal;			// Input binormal vector attribute

void main( void )
{
	gl_Position = ftransform();
	Texcoord    = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;

	vec4 fvObjectPosition = gl_ModelViewMatrix * gl_Vertex;
	vec3 fvViewDirection  = fvEyePosition - fvObjectPosition.xyz;
	vec3 fvLightDirection = gl_LightSource[0].position.xyz - fvObjectPosition.xyz;

	vec3 fvTangent        = gl_NormalMatrix * ifvTangent;
	vec3 fvBinormal       = gl_NormalMatrix * ifvBinormal;
	vec3 fvNormal         = gl_NormalMatrix * gl_Normal;

	Distance         = distance( gl_LightSource[0].position.xyz, fvObjectPosition.xyz );

	ViewDirection.x  = dot( fvTangent, fvViewDirection );
	ViewDirection.y  = dot( fvBinormal, fvViewDirection );
	ViewDirection.z  = dot( fvNormal, fvViewDirection );

	LightDirection.x  = dot( fvTangent, fvLightDirection.xyz );
	LightDirection.y  = dot( fvBinormal, fvLightDirection.xyz );
	LightDirection.z  = dot( fvNormal, fvLightDirection.xyz );
}

-- `PhongBlinn.Fragment`	// Fragment shader definition of the Phong-Blinn lighting model effect

#ifdef DO_BUMP_MAPPING
uniform sampler2D sBumpMap;
#define SampleNormal(texCoord) (normalize((2.0 * texture2D(sBumpMap,texCoord).xyz) - 1.0))
#else
#define SampleNormal(texCoord) vec3(0.0,0.0,1.0)
#endif

uniform sampler2D sBaseMap;
uniform sampler2D sSpecularMap;

out vec4 FragColor;

in vec2 Texcoord;
in vec3 ViewDirection;
in vec3 LightDirection;
in float Distance;

void main( void )
{
	vec3 fvLightDirection = normalize( LightDirection );
	vec3 fvViewDirection = normalize( ViewDirection );
	vec3 fvHalf = normalize( fvLightDirection + fvViewDirection );
   
	vec3 fvNormal = SampleNormal( Texcoord );
   
	float fNDotL = max ( 0.0, dot( fvNormal, fvLightDirection ) );
	float fNDotH = max ( 0.0, dot( fvNormal, fvHalf ) );

	vec4 fvTotalDiffuse = gl_LightSource[0].diffuse * fNDotL;
	vec4 fvTotalSpecular = gl_LightSource[0].specular * ( pow( fNDotH, gl_FrontMaterial.shininess ) ) * texture2D( sSpecularMap, Texcoord );
   
	float fAttenuation = 1.0 / (gl_LightSource[0].constantAttenuation +
								gl_LightSource[0].linearAttenuation * Distance +
								gl_LightSource[0].quadraticAttenuation * Distance * Distance);

	FragColor = 2.0 * ((fvTotalDiffuse + fvTotalSpecular) * fAttenuation) * texture2D( sBaseMap, Texcoord );
}

-- `SimpleScatter.Fragment`

#ifdef DO_BUMP_MAPPING
uniform sampler2D sBumpMap;
#define SampleNormal(texCoord) (normalize((2.0 * texture2D(sBumpMap,texCoord).xyz) - 1.0))
#else
#define SampleNormal(texCoord) vec3(0.0,0.0,1.0)
#endif

uniform sampler2D sBaseMap;
uniform sampler2D sSpecularMap;
uniform sampler2D sDepthMap;

uniform float fScatterBias;
uniform float fScatterScale;

out vec4 FragColor;

in vec2 Texcoord;
in vec3 ViewDirection;
in vec3 LightDirection;
in float Distance;

void main( void )
{
	vec3 fvLightDirection = normalize( LightDirection );
	vec3 fvViewDirection = normalize( ViewDirection );
	vec3 fvHalf = normalize( fvLightDirection + fvViewDirection );
   
	vec3 fvNormal = SampleNormal( Texcoord );
   
	float fNDotL = max ( 0.0, dot( fvNormal, fvLightDirection ) );
	float fNDotH = max ( 0.0, dot( fvNormal, fvHalf ) );
	
	float fScatteringPowerD = fScatterScale * texture2D( sDepthMap, Texcoord ).r + fScatterBias;
	float fScatteringPowerS = 10.0 * fScatteringPowerD;

	vec4 fvTotalDiffuse = gl_LightSource[0].diffuse * ( fNDotL + fScatteringPowerD );
	vec4 fvTotalSpecular = gl_LightSource[0].specular * ( pow( fNDotH, gl_FrontMaterial.shininess + fScatteringPowerS ) ) * texture2D( sSpecularMap, Texcoord );
   
	float fAttenuation = 2.0 / (gl_LightSource[0].constantAttenuation +
								gl_LightSource[0].linearAttenuation * Distance +
								gl_LightSource[0].quadraticAttenuation * Distance * Distance);

	FragColor = ((fvTotalDiffuse + fvTotalSpecular) * fAttenuation) * texture2D( sBaseMap, Texcoord );
}

-- `FSSS.Fragment`

#ifdef DO_BUMP_MAPPING
uniform sampler2D sBumpMap;
#define SampleNormal(texCoord) (normalize((2.0 * texture2D(sBumpMap,texCoord).xyz) - 1.0))
#else
#define SampleNormal(texCoord) vec3(0.0,0.0,1.0)
#endif

uniform sampler2D sBaseMap;
uniform sampler2D sSpecularMap;
uniform sampler2D sDepthMap;

uniform float fScatterBias;
uniform float fScatterScale;
uniform float fSpecularBias;
uniform float fSpecularPower;

out vec4 FragColor;

in vec2 Texcoord;
in vec3 ViewDirection;
in vec3 LightDirection;
in float Distance;

void main( void )
{
	vec3 fvLightDirection = normalize( LightDirection );
	vec3 fvViewDirection = normalize( ViewDirection );
	vec3 fvHalf = normalize( fvLightDirection + fvViewDirection );
	vec3 fvNormal = SampleNormal( Texcoord );
      
	float fScattering = fScatterScale * texture2D( sDepthMap, Texcoord ).r + fScatterBias;
	vec3 fvND = normalize ( fvNormal + fvViewDirection * fScattering );
	vec3 fvNS = normalize ( fvNormal + fvHalf * fScattering );
   
	float fNDotL = max ( 0.0, dot( fvND, fvLightDirection ) );
	float fNDotH = max ( 0.0, dot( fvNS, fvHalf ) );
	float fSpec = pow (exp (fSpecularPower * (fNDotH - 1.0)) + fSpecularBias, gl_FrontMaterial.shininess );
	//float fSpec = pow( fNDotH, gl_FrontMaterial.shininess );

	vec4 fvTotalDiffuse = gl_LightSource[0].diffuse * ( fNDotL );
	vec4 fvTotalSpecular = gl_LightSource[0].specular * ( fSpec ) * texture2D( sSpecularMap, Texcoord );
   
	float fAttenuation = 2.0 / (gl_LightSource[0].constantAttenuation +
								gl_LightSource[0].linearAttenuation * Distance +
								gl_LightSource[0].quadraticAttenuation * Distance * Distance);

	// Specular and diffuse colors for the skin effect can be sampled from texture3D according to the given depth value
	FragColor = ((fvTotalDiffuse + fvTotalSpecular) * fAttenuation) * texture2D( sBaseMap, Texcoord );
}
